This invention generally relates to the field of application program development, and more particularly to providing automatic support for undo, redo and abort transactions in a programming environment.
Providing support for undo, redo and abort transactions in an application program is traditionally a complex and error-prone task. For highly complex application programs, such as Computer Aided Design (CAD) projects, the task is particularly difficult. One reason for this difficulty is that CAD designs are frequently revised before a design is deemed completed. For example, designs frequently evolve and change according to revised design goals or when certain features do not yield desired results. Thus, in any particular design session, a designer may make many substantial changes to a design, where each change may then require changes to other components of the design. Consequently, implementation of a robust undo, redo or abort system becomes correspondingly complex. (For brevity, the term xe2x80x9cundoxe2x80x9d, unless indicated otherwise by wording or context, refers to undo, redo, and abort operations performed by an application program. The term xe2x80x9creversionxe2x80x9d will be used to refer to program code implementing such undo, redo, and abort support.)
Part of the reason for the difficulty in providing undo support in a solid modeling system is that there are no inverse operations for most Boolean operations applied to objects within a model. Hence, one must capture the details of what has changed at a very low level, e.g., at the data structure level. In addition, many user operations are often ill formed, causing the operation to fail after partial calculation of the user request, and leaving the model in an unstable state that requires correction.
Historically, there have been several methods of incorporating undo support within the source code of an application program. The simplest (and most limiting) has been to save to permanent storage a check-point version of a design in progress. This saved copy can be re-loaded if the design goes awry. There are significant problems with this approach, however. First, restorations are limited to the design as saved. Second, designs can be extremely complex, and significant resources (e.g., processor, memory, storage, etc.) and time can be required to save and re-load designs; this limits the frequency of such backups.
An improved method has been to utilize an object-based history mechanism. That is, design environments typically break a drawing into multiple objects, frequently arranged as a graph. Drawing objects can be made responsible for saving current state information before effecting a change to its state. The saved state information can be used to revert an object to a previous state. However, this approach also suffers several significant shortcomings. One shortcoming is that every object must properly handle reversions (e.g., have appropriate program code to perform an undo). Similar to a chain being only as strong as the weakest link, an entire undo mechanism can be compromised by one object""s failure to properly restore its state. Another is that every object must consume Central Processing Unit (CPU) resources to effect the state saving, and may seriously degrade program performance.
Another method has been to maintain a list of inverse operations. If a user rotates an object by ninety degrees, an inverse operation is recorded to undo the rotation. But, this method has shortcomings. One is that performing an inverse operation is generally at least as resource consuming as the original calculation to get to the current state. Another, more problematic shortcoming, is that some operations have no inverse. For example, application of a lossy filter discards original data that cannot be recovered.
Yet another method has been to maintain a history of design actions, where a reversion is effected by re-computing the entire design up to some previous state. This solution is similar to applying inverse operations, and overcomes the problem with lossy operations. However, operations relying on real-time, transient, or random data still cannot be reversed. And, since a design may have a very large number of operations to recreate, this solution can also be extremely slow and resource intensive.
But, each of the above methods places a burden on an application program designer (e.g., the CAD/CAM developer) to design and implement a complex reversion feature. Due to such complexity, a significant portion of application program design time can be expended in order to properly implement it and allow its use throughout the application program. Also, there is no guarantee that it will be implemented correctly. And, since such a feature is integral to an application program, it is unlikely that resulting program code will be easily portable to a different application program.
A programming environment can be modified to provide automatic support for reverting program memory states. Such memory reversions are used to provide automatic support for undo, redo, and abort operations for application programs written with the programming environment. Memory allocation code (e.g., functions, procedures, etc.) can be modified to mark allocated memory as protected, and assign an exception handler to such memory. For example, a Microsoft Win32 exception filter can be associated with a memory region. (An exception filter decides, based on the exception details, whether the exception represents an attempt to modify memory which we have protected (as opposed to any other memory, or other kind of exception).) An attempt to access the memory causes an exception to be generated; in the Win32 context, a memory management heap id made responsible for tracking whether accesses generate violations. This exception is caught (e.g., Win32 Structured Exception Handling), providing opportunity for the memory to be preserved before it is modified, and program execution continued. Previous program states can be retrieved by restoring such stored memory states.